package com.seer.auto.controller;

import com.seer.auto.dto.ErrorCode;
import com.seer.auto.dto.Response;
import com.seer.auto.error.BusinessException;
import java.io.File;
import javax.xml.bind.ValidationException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.validation.BindingResult;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingRequestHeaderException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

@ControllerAdvice
@Slf4j
public class BaseController implements ResponseBodyAdvice<Object> {

    @ExceptionHandler(value = HttpRequestMethodNotSupportedException.class)
    @ResponseBody
    public Response exception(HttpRequestMethodNotSupportedException e) {
        log.info("Method Error={}", e.getMessage());
        return Response.error(ErrorCode.UNIMPLEMENTED.with("不支持 " + e.getMethod() + " 请求"));
    }

    @ExceptionHandler(value = MethodArgumentTypeMismatchException.class)
    @ResponseBody
    public Response exception(MethodArgumentTypeMismatchException e) {
        log.info("Method Error={}", e.getMessage());
        return Response.error(ErrorCode.UNIMPLEMENTED.with("不支持该接口"));
    }

    @ExceptionHandler(value = HttpMessageNotReadableException.class)
    @ResponseBody
    public Response exception(HttpMessageNotReadableException e) {
        log.info("Argument Error={}", e.getMessage());
        return Response.error(ErrorCode.INVALID_ARGUMENT.with("请求格式错误"));
    }

    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    @ResponseBody
    public Response exception(MethodArgumentNotValidException e) {
        // e.printStackTrace();
        BindingResult result = e.getBindingResult();
        String msg = "";
        if (result.hasErrors()) {
            msg = result.getFieldErrors().get(0).getDefaultMessage();
        }
        log.info("argument error: {}", e.getMessage());
        log.debug("fail: {}", Response.error(ErrorCode.INVALID_ARGUMENT.with(msg)));
        return Response.error(ErrorCode.INVALID_ARGUMENT.with(msg));
    }

    @ExceptionHandler(value = ValidationException.class)
    @ResponseBody
    public Response exception(ValidationException e) {
        log.info("argument error={}", e.getMessage());
        String[] msg = e.getMessage().split(":");
        log.debug("fail: {}",
            Response.error(ErrorCode.INVALID_ARGUMENT.with(msg[msg.length - 1].trim())));
        return Response.error(ErrorCode.INVALID_ARGUMENT.with(msg[msg.length - 1].trim()));
    }

    @ExceptionHandler(value = MissingRequestHeaderException.class)
    @ResponseBody
    public Response exception(MissingRequestHeaderException e) {
        log.info("header error={}", e.getMessage());
        log.debug("fail: {}",
            Response.error(ErrorCode.INVALID_ARGUMENT.with(e.getHeaderName() + " 头信息不能为空")));
        return Response.error(ErrorCode.INVALID_ARGUMENT.with(e.getHeaderName() + " 头信息不能为空"));
    }

    @ExceptionHandler
    @ResponseBody
    public Response exception(Exception e) {
        if (e instanceof BusinessException) {
            log.info("{}, error={}",((BusinessException) e).code().getMsg(), e.getMessage());
            return Response.error(
                ((BusinessException) e).code().with(((BusinessException) e).error()));
        }
        log.info("system error={}", e.getMessage());
        log.debug("fail: {}", Response.error(ErrorCode.UNKNOWN.with("未知错误")));
        return Response.error(ErrorCode.UNKNOWN.with("未知错误"));
    }

    @ExceptionHandler(value = HttpMediaTypeNotSupportedException.class)
    @ResponseBody
    public Response exception(HttpMediaTypeNotSupportedException e) {
        log.info("body error={}", e.getMessage());
        log.debug("fail: {}", Response.error(ErrorCode.INVALID_ARGUMENT.with(e.getMessage())));
        return Response.error(ErrorCode.INVALID_ARGUMENT.with("请求不支持该参数格式"));
    }

    @ExceptionHandler(value = MissingServletRequestParameterException.class)
    @ResponseBody
    public Response exception(MissingServletRequestParameterException e) {
        log.info("parameter exception={}", e.getMessage());
        return Response.error(ErrorCode.INVALID_ARGUMENT.with("缺少参数 " + e.getParameterName()));
    }

    @Override
    public boolean supports(MethodParameter returnType,
        Class<? extends HttpMessageConverter<?>> converterType) {
        return MappingJackson2HttpMessageConverter.class.isAssignableFrom(converterType);
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType,
        MediaType selectedContentType,
        Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request,
        ServerHttpResponse response) {
        if (body == null) {
            return Response.ok(null);
        }

        if (body instanceof Response) {
            return body;
        } else if (body instanceof File) {
            return body;
        } else {
            return Response.ok(body);
        }
    }
}
